//
//  UIImage+Extension.m
//  TableDemo
//
//  Created by jutuo on 2020/3/26.
//  Copyright © 2020 jutuo. All rights reserved.
//

#import "UIImage+Extension.h"
#import <Photos/Photos.h>

@implementation UIImage (Extension)
+ (nullable UIImage *)imageWithColor:(UIColor *)color
{
    return [self imageWithColor:color size:CGSizeMake(1, 1)];
}
+ (nullable UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size
{
    if (!color || size.width < 0 || size.height <= 0) {
        return nil;
    }
    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
+ (UIImage *)gradientImageWithPath:(CGPathRef)path colors:(NSArray*)colors gradientDirectionType:(GradientDirectionType)gradientDirection
{
    NSMutableArray *cgColors = [NSMutableArray array];
    for (UIColor *color in colors) {
        [cgColors addObject:(__bridge id)color.CGColor];
    }
    CGRect pathRect = CGPathGetBoundingBox(path);
    UIGraphicsBeginImageContextWithOptions(pathRect.size, YES, 1);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextAddPath(context, path);
    CGContextClip(context);
    CGColorSpaceRef colorSpace = CGColorGetColorSpace([[colors lastObject] CGColor]);
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)cgColors, NULL);
    CGPoint startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMinY(pathRect));
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMinY(pathRect));
    switch (gradientDirection) {
        case GradientLeftToRight:
            startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMinY(pathRect));
            endPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMinY(pathRect));
            break;
        case GradientLeftTopToRightBottom:
            startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMinY(pathRect));
            endPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMaxY(pathRect));
            break;
        case GradientLeftBottomToRightTop:
            startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMaxY(pathRect));
            endPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMinY(pathRect));
            break;
        case GradientRightToLeft:
            startPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMinY(pathRect));
            endPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMinY(pathRect));
            break;
        case GradientRightTopToLeftBottom:
            startPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMinY(pathRect));
            endPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMaxY(pathRect));
            break;
        case GradientRightBottomToLeftTop:
            startPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMaxY(pathRect));
            endPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMinY(pathRect));
            break;
        case GradientTopToBottom:
            startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMinY(pathRect));
            endPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMaxY(pathRect));
            break;
        case GradientBottomToTop:
            startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMaxY(pathRect));
            endPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMinY(pathRect));
            break;
        default:
            break;
    }
    
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    CGGradientRelease(gradient);
    CGContextRestoreGState(context);
    CGColorSpaceRelease(colorSpace);
    CGPathRelease(path);
    UIGraphicsEndImageContext();
    return image;
}

+ (UIImage *)gradientImageWithRect:(CGRect)rect colors:(NSArray*)colors gradientDirectionType:(GradientDirectionType)gradientDirection
{
    NSMutableArray *cgColors = [NSMutableArray array];
    for (UIColor *color in colors) {
        [cgColors addObject:(__bridge id)color.CGColor];
    }
    UIGraphicsBeginImageContextWithOptions(rect.size, YES, 1);
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGColorSpaceRef colorSpace = CGColorGetColorSpace([[colors firstObject] CGColor]);
    CGContextScaleCTM(context, rect.size.width, rect.size.height);
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)cgColors, NULL);
    CGPoint startPoint = CGPointMake(0, 0);
    CGPoint endPoint = CGPointMake(1, 1);
    switch (gradientDirection) {
        case GradientLeftToRight:
            startPoint = CGPointMake(0, 0);
            endPoint = CGPointMake(1, 0);
            break;
        case GradientLeftTopToRightBottom:
            startPoint = CGPointMake(0, 0);
            endPoint = CGPointMake(1, 1);
            break;
        case GradientLeftBottomToRightTop:
            startPoint = CGPointMake(0, 1);
            endPoint = CGPointMake(1, 0);
            break;
        case GradientRightToLeft:
            startPoint = CGPointMake(1, 0);
            endPoint = CGPointMake(0, 0);
            break;
        case GradientRightTopToLeftBottom:
            startPoint = CGPointMake(1, 0);
            endPoint = CGPointMake(0, 1);
            break;
        case GradientRightBottomToLeftTop:
            startPoint = CGPointMake(1, 1);
            endPoint = CGPointMake(0, 0);
            break;
        case GradientTopToBottom:
            startPoint = CGPointMake(0, 0);
            endPoint = CGPointMake(0, 1);
            break;
        case GradientBottomToTop:
            startPoint = CGPointMake(0, 1);
            endPoint = CGPointMake(0, 0);
            break;
        default:
            break;
    }
        
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation);
    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
        
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
+ (UIImage *)imageWithEmoji:(NSString *)emoji size:(CGFloat)size
{
    if (emoji.length == 0) return nil;
    if (size < 1) return nil;
    
    CGFloat scale = [UIScreen mainScreen].scale;
    CTFontRef font = CTFontCreateWithName(CFSTR("AppleColorEmoji"), size * scale, NULL);
    if (!font) return nil;
    
    NSAttributedString *str = [[NSAttributedString alloc]initWithString:emoji attributes:@{(__bridge id)kCTFontAttributeName : (__bridge id)font,(__bridge id)kCTForegroundColorAttributeName : (__bridge id)[UIColor whiteColor].CGColor}];
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(NULL, size * scale, size * scale, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
    CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);
    CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)str);
    CGRect bounds = CTLineGetBoundsWithOptions(line, kCTLineBoundsUseGlyphPathBounds);
    CGContextSetTextPosition(ctx, 0, -bounds.origin.y);
    CTLineDraw(line, ctx);
    
    CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
    UIImage *image = [[UIImage alloc]initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
    CFRelease(font);
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(ctx);
    if (line) CFRelease(line);
    if (imageRef) CFRelease(imageRef);
    return image;
}
+ (UIImage *)imageWithPDF:(id)dataOrPath page:(size_t)pageNum
{
    return [self _xy_imageWithPDF:dataOrPath resize:NO size:CGSizeZero page:pageNum];
}
+ (UIImage *)imageWithPDF:(id)dataOrPath size:(CGSize)size page:(size_t)pageNum
{
    return [self _xy_imageWithPDF:dataOrPath resize:YES size:size page:pageNum];
}
+ (UIImage *)_xy_imageWithPDF:(id)dataOrPath resize:(BOOL)resize size:(CGSize)size page:(size_t)pageNum
{
    CGPDFDocumentRef pdf = NULL;
    if ([dataOrPath isKindOfClass:[NSData class]]) {
        CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)dataOrPath);
        pdf = CGPDFDocumentCreateWithProvider(provider);
    }else if ([dataOrPath isKindOfClass:[NSString class]]){
        pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:dataOrPath]);
    }
    if (!pdf) return nil;
    
    CGPDFPageRef page = CGPDFDocumentGetPage(pdf, pageNum);
    if (!page) {
        CGPDFDocumentRelease(pdf);
        return nil;
    }
    
    CGRect pdfRect = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
    CGSize pdfSize = resize ? size : pdfRect.size;
    CGFloat scale = [UIScreen mainScreen].scale;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(NULL, pdfSize.width * scale, pdfSize.height * scale, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
    if (!ctx) {
        CGColorSpaceRelease(colorSpace);
        CGPDFDocumentRelease(pdf);
        return nil;
    }
    
    CGContextScaleCTM(ctx, scale, scale);
    CGContextTranslateCTM(ctx, -pdfRect.origin.x, -pdfRect.origin.y);
    CGContextDrawPDFPage(ctx, page);
    CGPDFDocumentRelease(pdf);
    
    CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
    UIImage *pdfImage = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
    CFRelease(imageRef);
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
    return pdfImage;
}
// 截取部分图像
- (UIImage *)cutOutSubImage:(CGRect)rect
{
    CGImageRef subImageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
    CGRect smallBounds = CGRectMake(0, 0, CGImageGetWidth(subImageRef), CGImageGetHeight(subImageRef));
    UIGraphicsBeginImageContext(smallBounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawImage(context, smallBounds, subImageRef);
    UIImage *smallImage = [UIImage imageWithCGImage:subImageRef];
    UIGraphicsEndImageContext();
    return smallImage;
}
- (UIImage *)imageByTintColor:(UIColor *_Nullable)color
{
    return [self imageByTintColor:color size:CGSizeZero];
}
- (UIImage *)imageByTintColor:(UIColor * _Nullable)color size:(CGSize)size
{
    if (!color) return nil;
    CGSize imgSize = (size.width > 0 && size.height > 0) ? size : self.size;
    CGRect rect = CGRectMake(0, 0, imgSize.width, imgSize.height);
    
    UIGraphicsBeginImageContextWithOptions(imgSize, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0, self.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    CGContextClipToMask(context, rect, self.CGImage);
    [color setFill];
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
    
}
- (UIImage *)imageByResizeToSize:(CGSize)size
{
    if (size.width <= 0 || size.height <= 0) return nil;
    UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
    [self drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
- (UIImage *)imageByScale:(CGFloat)scale
{
    CGFloat scaleWidth = self.size.width * scale;
    CGFloat scaleHeight = self.size.height * scale;
    CGSize scaleSize = CGSizeMake(scaleWidth, scaleHeight);
    return [self imageByResizeToSize:scaleSize];
}
- (UIImage *)imageByInsetEdge:(UIEdgeInsets)insets withColor:(UIColor *)color
{
    CGSize size = self.size;
    size.width -= insets.left + insets.right;
    size.height -= insets.top + insets.bottom;
    if (size.width <= 0 || size.height <= 0) return nil;
    CGRect rect = CGRectMake(-insets.left, -insets.top, self.size.width, self.size.height);
    UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    if (color) {
        CGContextSetFillColorWithColor(context, color.CGColor);
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathAddRect(path, NULL, CGRectMake(0, 0, size.width, size.height));
        CGPathAddRect(path, NULL, rect);
        CGContextAddPath(context, path);
        CGContextEOFillPath(context);
        CGPathRelease(path);
    }
    [self drawInRect:rect];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius
{
    return [self imageByRoundCornerRadius:radius borderWidth:0 borderColor:nil];
}
- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius
borderWidth:(CGFloat)borderWidth
                          borderColor:(UIColor * _Nullable)borderColor
{
    return [self imageByRoundCornerRadius:radius
                                     corners:UIRectCornerAllCorners
                                 borderWidth:borderWidth
                                 borderColor:borderColor
                              borderLineJoin:kCGLineJoinMiter];
}

- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius
       corners:(UIRectCorner)corners
   borderWidth:(CGFloat)borderWidth
   borderColor:(UIColor *_Nullable)borderColor
borderLineJoin:(CGLineJoin)borderLineJoin
{
    if (corners != UIRectCornerAllCorners) {
        UIRectCorner tmp = 0;
        if (corners & UIRectCornerTopLeft) tmp |= UIRectCornerBottomLeft;
        if (corners & UIRectCornerTopRight) tmp |= UIRectCornerBottomRight;
        if (corners & UIRectCornerBottomLeft) tmp |= UIRectCornerTopLeft;
        if (corners & UIRectCornerBottomRight) tmp |= UIRectCornerTopRight;
        corners = tmp;
    }
    
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -rect.size.height);
    
    CGFloat minSize = MIN(self.size.width, self.size.height);
    if (borderWidth < minSize / 2) {
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:CGSizeMake(radius, borderWidth)];
        [path closePath];
        
        CGContextSaveGState(context);
        [path addClip];
        CGContextDrawImage(context, rect, self.CGImage);
        CGContextRestoreGState(context);
    }
    
    if (borderColor && borderWidth < minSize / 2 && borderWidth > 0) {
        CGRect strokeRect = CGRectInset(rect, borderWidth, borderWidth);
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(radius, borderWidth)];
        [path closePath];
        path.lineWidth = borderWidth;
        path.lineJoinStyle = borderLineJoin;
        [borderColor setStroke];
        [path stroke];
    }
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

/**
 获取网络视频的任意时间帧图片
 */
+ (void)imageByVideoUrl:(NSURL *)videoURL atTime:(NSTimeInterval)time completion:(void (^)(UIImage*))handler
{
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
        
        AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
        
        generator.appliesPreferredTrackTransform = YES;
        
        CMTime time = CMTimeMakeWithSeconds(0.0, 600);
        
        NSError *error = nil;
        
        CMTime actualTime;
        
        CGImageRef imageRef = [generator copyCGImageAtTime:time actualTime:&actualTime error:&error];
        
        UIImage *thumb = [[UIImage alloc] initWithCGImage:imageRef];
        
        CGImageRelease(imageRef);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            handler(thumb);
        });
    });
}
@end

@implementation UIImage (Gif)
static float frameDurationAtIndex(NSInteger index ,CGImageSourceRef const source)
{
    float frameDuration = 0;
    CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, (size_t)index, NULL);
    NSDictionary *frameProperties = (__bridge NSDictionary *) cfFrameProperties;
    NSDictionary *gifProperties = frameProperties[(__bridge NSString *)kCGImagePropertyGIFDictionary];
    NSNumber *delayTimeUnclampedProp = gifProperties[(__bridge NSString *) kCGImagePropertyGIFUnclampedDelayTime];
    if (delayTimeUnclampedProp) {
        frameDuration = [delayTimeUnclampedProp floatValue];
    }else{
        NSNumber *delayTimeProp = gifProperties[(__bridge NSString *)kCGImagePropertyGIFDelayTime];
        if (delayTimeProp) {
            frameDuration = [delayTimeProp floatValue];
        }
        
    }
    if (frameDuration < 0.011f) {
           frameDuration = 0.100f;
       }
       
       CFRelease(cfFrameProperties);
       return frameDuration;
    
}

static UIImage *getGifImageWithImageSource(CGImageSourceRef const source ,CGFloat scale)
{
    size_t const count = CGImageSourceGetCount(source);
    NSMutableArray *images = [NSMutableArray array]
    ;
    CGFloat sumDuration = 0;
    UIImage *animatedImage = nil;
    for (NSInteger i = 0; i < (NSInteger)count; i++)
    {
        CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
        if (!image) {
            continue;
        }
        sumDuration += frameDurationAtIndex(i, source);
        [images addObject:[UIImage imageWithCGImage:image scale:scale orientation:UIImageOrientationUp]];
        CFRelease(image);
        
    }
    if (!sumDuration) {
           sumDuration = 0.1 * count;
       }
    animatedImage = [UIImage animatedImageWithImages:images duration:sumDuration];
    CFRelease(source);
       
    return animatedImage;
}
/**
 * 获取gif图片
 * @param data gif data;
 */
+ (UIImage *)getGifImageWithGIFData:(NSData *)data scale:(CGFloat)scale
{
    return getGifImageWithImageSource(CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL),scale);
}
/**
 * 获取gif图片
 * @param url gif url;
 */
+ (UIImage *)getGifImageWithGIFURL:(NSURL *)url scale:(CGFloat)scale;
{
    return getGifImageWithImageSource(CGImageSourceCreateWithURL((__bridge CFURLRef)url , NULL),scale);
}


@end
